#include "glwidget.h"

RenderThread::RenderThread(GLWidget* screen, glFullScreenWindow* fsDisplay, Video* v) :
    QThread(screen), screen(screen), fsDisplay(fsDisplay), v(v)
{
    v->videoClock = 0;
    v->vidTimeElapsed = 0;
    v->countingTime = QTime::currentTime();
    videoLength = (double)v->formatCtx->duration / AV_TIME_BASE; //* av_q2d(v->formatCtx->streams[v->videoIndex]->time_base);
}

void RenderThread::run() {
    int curHeight;
    int curWidth;
    if (fsDisplay->isHidden()) {
        curHeight = screen->height();
        curWidth = screen->width();
        screen->makeCurrent();
    }
    else {
        curHeight = fsDisplay->height();
        curWidth = fsDisplay->width();
        fsDisplay->getDisplay()->makeCurrent();
    }
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glViewport(0, 0, curWidth, curHeight);
    glMatrixMode(GL_PROJECTION);
    double hori_scale;
    double vert_scale;
    if ((double)curWidth * v->aspect_ratio > curHeight) {
        hori_scale = (double)curHeight / (v->aspect_ratio * (double)curWidth);
        vert_scale = 1;
    }
    else {
        hori_scale = 1;
        vert_scale = (v->aspect_ratio * (double)curWidth) / (double)curHeight;
    }

    //loop
    while (true) {
        sleep(0.002);
        AVFrame* frame;
        if (v->state == STOPPED) {
            break;
        }
        else if (v->state == PAUSED) {
            v->countingTime = QTime::currentTime();
            v->videoClock += v->vidTimeElapsed;
            v->vidTimeElapsed = 0;
            continue;
        }
        else if (v->state == PLAY || v->state == STOPPING) {
            if (v->pQueue->size == 0) {
                if (v->state == PLAY) {
                    sleep(0.005);
                    continue;
                }
                else if (v->state == STOPPING) {
                    break;
                }
            }
            v->vidTimeElapsed = (double)v->countingTime.msecsTo(QTime::currentTime())/1000;
            v->pQueue->mutex->lock();
            double pts = v->pQueue->curpts();
            if (pts != 0 && v->videoClock+v->vidTimeElapsed > pts) {
                if (v->pQueue->pop(&frame, &pts) < 0) {
                    v->pQueue->mutex->unlock();
                    continue;
                }

                v->pQueue->mutex->unlock();
            }
            else {
                v->pQueue->mutex->unlock();
                continue;
            }

            int prevWidth = curWidth;
            int prevHeight = curHeight;
            if (fsDisplay->isHidden()) {
                curWidth = screen->width();
                curHeight = screen->height();
                screen->makeCurrent();
            }
            else {
                curWidth = fsDisplay->width();
                curHeight = fsDisplay->height();
                fsDisplay->getDisplay()->makeCurrent();
            }

            if (prevWidth != curWidth || prevHeight != curHeight) {

                if ((double)curWidth * v->aspect_ratio > curHeight) {
                    hori_scale = (double)curHeight / (v->aspect_ratio * (double)curWidth);
                    vert_scale = 1;
                }
                else {
                    hori_scale = 1;
                    vert_scale = (v->aspect_ratio * (double)curWidth) / (double)curHeight;
                }
                glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
                glViewport(0, 0, curWidth, curHeight);
                glMatrixMode(GL_PROJECTION);
            }
            GLuint tex;
            glLoadIdentity();
            glGenTextures(1, &tex);
            glBindTexture(GL_TEXTURE_2D, tex);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexImage2D(GL_TEXTURE_2D, 0, 3, v->vCodecCtx->width, v->vCodecCtx->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame->data[0]);
            glEnable(GL_TEXTURE_2D);
            glPushMatrix();
            glBindTexture(GL_TEXTURE_2D, tex);
            glBegin(GL_QUADS);
            glTexCoord2i(0, 0); glVertex2d(-hori_scale, vert_scale);
            glTexCoord2i(1, 0); glVertex2d(hori_scale, vert_scale);
            glTexCoord2i(1, 1); glVertex2d(hori_scale, -vert_scale);
            glTexCoord2i(0, 1); glVertex2d(-hori_scale, -vert_scale);
            glEnd();
            glDeleteTextures(1, &tex);
            glPopMatrix();
            glDisable(GL_TEXTURE_2D);

            if (fsDisplay->isHidden())
                screen->swapBuffers();
            else
                fsDisplay->getDisplay()->swapBuffers();
            av_freep(frame);
            //1000 is the slider's max value
            emit setSlider((int)(pts*1000/videoLength));
        }
    }


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    screen->swapBuffers();
    emit finishRender();
    std::cout << "render thread finished" << std::endl;
}
